#ifndef __BSP_H
#define __BSP_H

#include "main.h"
#include "Version.h"
#ifdef GD32F4XX
#include "gd32f4xx.h"
#include "gd32f4xx_libopt.h"
#elif defined(GD32F20X)
#include "gd32f20x.h"
#include "gd32f20x_libopt.h"
#elif defined(GD32F10X)
#include "gd32f10x.h"
#include "gd32f10x_libopt.h"
#elif defined(GD32F3X0)
#include "gd32f3x0.h"
#include "gd32f3x0_libopt.h"
#elif defined(STM32F0)
#include "stm32f0xx_ll_bus.h"
#include "stm32f0xx_ll_rcc.h"
#include "stm32f0xx_ll_system.h"
#include "stm32f0xx_ll_utils.h"
#include "stm32f0xx_ll_gpio.h"
#include "stm32f0xx_ll_adc.h"
#include "stm32f0xx_ll_usart.h"
#include "stm32f0xx_ll_flash.h"
#include "stm32f0xx_hal_iwdg.h"
#elif defined(STM32F1)
#include "stm32f1xx_ll_bus.h"
#include "stm32f1xx_ll_rcc.h"
#include "stm32f1xx_ll_system.h"
#include "stm32f1xx_ll_utils.h"
#include "stm32f1xx_ll_gpio.h"
#include "stm32f1xx_ll_adc.h"
#include "stm32f1xx_ll_usart.h"
#include "stm32f1xx_ll_tim.h"
#include "stm32f1xx_ll_spi.h"
#include "stm32f1xx_ll_adc.h"
#include "stm32f1xx_ll_dma.h"
//#include "stm32f1xx_ll_flash.h"
#include "stm32f1xx_hal_iwdg.h"
#elif defined(SWM32)
#include "SWM320.h"
#endif
#define bpsConfigASSERT( x ) if ((x) == 0) for( ;; )
#ifdef CMSIS_OS
    #include "cmsis_os.h"
#endif

#ifdef STM32F1
void SystemClock_Config(void);
#endif

#ifdef USE_GPIO
typedef void(*pfun)(void *);

typedef struct _s_outputport OutputPort;
struct _s_outputport{
#if defined(STM32F0) ||  defined(STM32F1) || defined(SWM32)
    GPIO_TypeDef * gpiox;
#elif defined(GD32F20X) || defined(GD32F10X) || defined(GD32F3X0)
    uint32_t gpiox;
#endif
    uint32_t gpio_pinx;
    OutputPort *handle;
    void (*init)(OutputPort *outputport);
    void (*set_bit)(OutputPort *outputport);
    void (*reset_bit)(OutputPort *outputport);   
    void (*write_bit)(OutputPort *outputport,uint8_t bit);   
    void (*toggle)(OutputPort *outputport);
};


typedef struct _s_afio_gpio AFIO_GPIO;
struct _s_afio_gpio{
#if defined(STM32F0) ||  defined(STM32F1) || defined(SWM32)
    GPIO_TypeDef * gpiox;
#elif defined(GD32F20X) || defined(GD32F10X) || defined(GD32F3X0)
    uint32_t gpiox;
#endif 
    uint32_t gpio_pinx;
    uint32_t gpio_af;
    void (*init)(AFIO_GPIO *afio_gpio);
};

typedef enum 
{
    MODE_GPIO = 0,
    MODE_EXTI = 1
} inputmode_typedef_enum;

typedef struct _s_inputport InputPort;
struct _s_inputport{
#if defined(STM32F0) ||  defined(STM32F1) || defined(SWM32)
    GPIO_TypeDef * gpiox;
#elif defined(GD32F20X) || defined(GD32F10X) || defined(GD32F3X0)
    uint32_t gpiox;
#endif
    uint32_t gpio_pinx;
    uint32_t exit_line;
    uint8_t  trig_type;
    uint8_t inputmode;
    void (*init)(InputPort *inputport);
    void (*exti_init)(InputPort *inputport);
    uint8_t (*read)(InputPort *inputport);
    pfun callback;
    void *arg;
};

typedef struct _s_opendrainport OpenDrainPort;
struct _s_opendrainport{
#if defined(STM32F0) ||  defined(STM32F1) || defined(SWM32)
    GPIO_TypeDef * gpiox;
#elif defined(GD32F20X) || defined(GD32F10X) || defined(GD32F3X0)
    uint32_t gpiox;
#endif
    uint32_t gpio_pinx;
    OutputPort output;
    InputPort  input;
    void (*init)(OpenDrainPort *opendrainport);
    uint8_t (*read)(OpenDrainPort *opendrainport);
    void (*set_bit)(OpenDrainPort *opendrainport);
    void (*reset_bit)(OpenDrainPort *opendrainport);   
    void (*toggle)(OpenDrainPort *opendrainport);
};

typedef struct _s_analogport AnalogPort;
struct _s_analogport{
#if defined(STM32F0) ||  defined(STM32F1) || defined(SWM32)
    GPIO_TypeDef * gpiox;
#elif defined(GD32F20X) || defined(GD32F10X) || defined(GD32F3X0)
    uint32_t gpiox;
#endif
    uint32_t gpio_pinx;
    void (*init)(AnalogPort *opendrainport);
};

typedef struct _s_led LED;
struct _s_led{
    struct _s_outputport outputport;
    uint8_t level;
    enum{low_level,high_level}Level;
    void (*init)(LED *led);
    void (*on)(LED *led);
    void (*off)(LED *led);   
    void (*toggle)(LED *led);
};

#if defined(STM32F0) ||  defined(STM32F1) || defined(SWM32)
OutputPort new_outport(GPIO_TypeDef * gpiox,uint32_t gpio_pinx);
OpenDrainPort new_opendrainport(GPIO_TypeDef * gpiox,uint32_t gpio_pinx);
InputPort new_inputport(GPIO_TypeDef * gpiox,uint32_t gpio_pinx,uint8_t inputmode,uint8_t trig_type);
LED new_led(GPIO_TypeDef * gpiox,uint32_t gpio_pinx,uint8_t level);
#elif defined(GD32F20X) || defined(GD32F10X) || defined(GD32F3X0)
OutputPort new_outport(uint32_t gpiox,uint32_t gpio_pinx);
OpenDrainPort new_opendrainport(uint32_t gpiox,uint32_t gpio_pinx);
InputPort new_inputport(uint32_t gpiox,uint32_t gpio_pinx,uint8_t inputmode,uint8_t trig_type);
LED new_led(uint32_t gpiox,uint32_t gpio_pinx,uint8_t level);
#endif

#endif

#ifdef USE_UART
#define RECV_MODE_FIX_IT 0
#define RECV_MODE_TIMEOUT_IT 1
#define RECV_MODE_DMA 2
typedef struct _s_uart UART;
struct _s_uart{
    struct _s_afio_gpio txd_pin;
#if defined(STM32F1) || defined(GD32F20X) || defined(GD32F10X)
    struct _s_inputport rxd_pin;
#else
    struct _s_afio_gpio rxd_pin;
#endif
#if defined(STM32F0) || defined(STM32F1)
    USART_TypeDef * uartx;
#elif defined(GD32F20X) || defined(GD32F10X) || defined(GD32F3X0)
    uint32_t uartx;
#endif  

    uint32_t baudrate;
    uint8_t isgetrecv;
    uint8_t RecvMode;
    uint8_t *recvbuf;
    uint16_t recvsize;
    uint16_t recvcnt;
    uint16_t rxtimeoutcnt;
    uint16_t rxtimeoutset;
    uint16_t timeout;
    pfun RecvCallBack;
    void *RecvCBArg;
    void (*init)(UART *uart);
    void (*senddata)(UART *uart,uint8_t data);
    void (*sendbuf)(UART *uart,uint8_t *buf,uint16_t len);
    void (*sendString)(UART *uart,char *buf);
#ifdef USE_PRINTF
    void (*printf)(UART *uart, const char* fmt, ...);
#endif
    void (*RecvFixCntIT)(UART *uart,uint8_t *buf,uint16_t size);
    void (*RecvTimeoutIT)(UART *uart,uint8_t *buf,uint16_t size,uint8_t timeout);
    void (*SetRecvCallBack)(UART *uart,pfun callback,void *arg);
#ifdef CMSIS_OS
    osSemaphoreId uart_recv_sem;
    uint8_t (*WaitforRecv)(UART *uart,uint32_t waittime);
#endif
};
#ifdef DEBUG
extern UART *log_uart;
void uart_set_log_uart(UART *uart);
#endif

#if defined(STM32F0) || defined(STM32F1)
UART new_uart(GPIO_TypeDef * txd_gpiox,uint32_t txd_gpio_pinx,GPIO_TypeDef * rxd_gpiox,uint32_t rxd_gpio_pinx,USART_TypeDef * uartx,uint32_t baudrate);
void Uart_Interrupt_Handle(UART *uart);
void Uart_timeout_Handle(UART *uart);
#elif defined(GD32F20X) || defined(GD32F10X) || defined(GD32F3X0)
UART new_uart(uint32_t txd_gpiox,uint32_t txd_gpio_pinx,uint32_t rxd_gpiox,uint32_t rxd_gpio_pinx,uint32_t uartx,uint32_t baudrate);
void Uart_Interrupt_Handle(UART *uart);
void Uart_timeout_Handle(UART *uart);
#endif  
#endif

#ifdef USE_SPI
typedef struct _s_spi SPI;
struct _s_spi{
    struct _s_afio_gpio sck;
    struct _s_afio_gpio miso;
    struct _s_afio_gpio mosi;
    uint8_t mode;              // SPI_CK_PL_LOW_PH_1EDGE  SPI_CK_PL_HIGH_PH_1EDGE   SPI_CK_PL_LOW_PH_2EDGE    SPI_CK_PL_HIGH_PH_2EDGE 
    uint8_t buadrate;
    SPI_TypeDef *spix;
    void (*init)(SPI *spi);
    uint16_t(*readwritebyte)(SPI *spi,uint16_t byte);
    void (*readwritebuf)(SPI* spi,uint8_t* TxBuf,uint8_t* RxBuf,uint8_t len);
    void (*SetSpeed)(SPI *spi,uint32_t baud);
    void (*SetMode)(SPI *spi,uint8_t mode);
    void (*Set_Frame_Bit)(SPI* spi,uint16_t framebit);
    void(*Quadspi_init)(SPI *spi,uint32_t spi_gpio,uint32_t spi_io2_pinx,uint32_t spi_io3_pinx);
};

SPI new_spi(GPIO_TypeDef* gpiox,uint32_t sck_pinx,uint32_t miso_pinx,uint32_t mosi_pinx,SPI_TypeDef* spix);//defaut mode = 0
#endif

#ifdef USE_ADC
#ifndef SUPPUT_ADC_CH 
#define SUPPUT_ADC_CH 16
#endif
struct _adc_chanel{
    GPIO_TypeDef * ch_gpiox;
    uint32_t ch_gpio_pinx;
    uint8_t chx;
#ifndef STM32F0
	 uint32_t SamplingTime;
#endif
};
#define ADC_POLL_MODE 0
#define ADC_IT_MODE 1
#define ADC_DMA_MODE 2
typedef struct _s_adc ADC_CTL;
struct _s_adc{
    ADC_TypeDef *adcx;
    IRQn_Type IRQn;
    uint16_t *buf;
    uint16_t bufsize;
    uint16_t bufcnt;
    pfun ConvCmpCallback;
    void *ConvCmpCBArg;
    void *Trigger;
    uint8_t IsCircular;
    uint32_t priority;
    uint8_t mode; //0 poll ;1 IT 2 DMA
    struct _adc_chanel adc_chanel[SUPPUT_ADC_CH];
    uint8_t used_chanel_num;
    void (*add_chanel)(ADC_CTL *adc,GPIO_TypeDef * ch_gpiox,uint32_t ch_gpio_pinx,uint32_t ch
#ifndef STM32F0
		,uint32_t SamplingTime
#endif
			);
    void (*init)(ADC_CTL *adc);
    void (*_adc_SoftwareTrigger)(ADC_CTL *adc);
    void (*SetTrigger)(ADC_CTL *adc,uint32_t trig_type,void * trigger);
    void (*StartIT)(ADC_CTL *adc,uint32_t priority);
    void (*StopIT)(ADC_CTL *adc);
    void (*StartDMA)(ADC_CTL *adc,uint8_t IsCircular);
    void (*StopDMA)(ADC_CTL *adc);
    void (*SetCallback)(ADC_CTL *adc,pfun callback,void *arg);
};
ADC_CTL new_adc(ADC_TypeDef *ADCx,uint16_t *buf,uint16_t size);
void ADCx_IRQHandler(ADC_CTL *adc);
void ADCx_DMA_IRQHandler(ADC_CTL *adc);
#endif

#ifdef USE_TIMER
typedef struct _s_Timer_base Timer_Base;
struct _s_Timer_base
{
	TIM_TypeDef *TIMx;
    pfun callback_handler;
    void *callback_arg;
    IRQn_Type IRQn;
	void (*init)(Timer_Base *timer_base,uint32_t clk,uint32_t frq);
	void (*start)(Timer_Base *timer_base);
	void (*stop)(Timer_Base *timer_base);
	void (*startIT)(Timer_Base *timer_base,uint32_t priority,void(*handle), void *arg);
	void (*stopIT)(Timer_Base *timer_base);
	uint32_t (*GetCounter)(Timer_Base *timer_base);
	void (*SetCounter)(Timer_Base *timer_base,uint32_t cnt);
    uint32_t (*GetReload)(Timer_Base *timer_base);
};
Timer_Base new_timer_base(TIM_TypeDef *timx, uint32_t clk, uint32_t frq);
void TIMx_IRQHandler(Timer_Base *timer_base);

#define TIMER_PWM_CH_NUM  4
#define TIMER_PWM_CH1     0
#define TIMER_PWM_CH2     1
#define TIMER_PWM_CH3     2
#define TIMER_PWM_CH4     3
#define M(x)  x*1000000
#define K(x)  x*1000
typedef struct _s_Timer_Pwm Timer_Pwm;
struct _s_Timer_Pwm
{
    Timer_Base timer_Base;
    pfun callback_handler;
    void *callback_arg;
    struct _s_afio_gpio ch_gpio[TIMER_PWM_CH_NUM];
    struct _s_afio_gpio ch_gpio_n[TIMER_PWM_CH_NUM];
    uint32_t channel[TIMER_PWM_CH_NUM];
    uint32_t channel_n[TIMER_PWM_CH_NUM];
    uint8_t ischannelpending[TIMER_PWM_CH_NUM];
	void (*init_channel)(Timer_Pwm *timer_pwm,uint8_t TIM_Channelx,uint16_t pwmpulse,GPIO_TypeDef *gpiox,uint32_t gpio_pinx);
    void (*init_channel_n)(Timer_Pwm *timer_pwm,uint8_t TIM_Channelx,GPIO_TypeDef *gpiox,uint32_t gpio_pinx);
	void (*SetPulse)(Timer_Pwm *timer_pwm,uint8_t TIM_Channelx,uint16_t pulse);
	void (*Start)(Timer_Pwm *timer_pwm,uint8_t TIM_Channelx);
	void (*Stop)(Timer_Pwm *timer_pwm,uint8_t TIM_Channelx);
    void (*StartIT)(Timer_Pwm *timer_pwm,uint8_t TIM_Channelx,uint32_t priority,void(*handle), void *arg);
	void (*StopIT)(Timer_Pwm *timer_pwm,uint8_t TIM_Channelx);
    void (*SetDeadtime)(Timer_Pwm *timer_pwm,uint16_t deadtime);
    void (*SetLocklevel)(Timer_Pwm *timer_pwm,uint8_t locklevel);
};

Timer_Pwm new_Timer_Pwm(TIM_TypeDef *timx, uint32_t clk, uint32_t frq);
void PWMx_IRQHandler(Timer_Pwm *timer_pwm);
#endif

#ifdef USE_WATCHDOG
#define HAL_IWDG_MODULE_ENABLED
struct _s_watchdog
{
    IWDG_HandleTypeDef hiwdg;
    void (*Init)(uint32_t time);
    void (*Feed)(void);
};
extern struct _s_watchdog watchdog;
#endif

/* Error code */
enum 
{
  FLASHIF_OK = 0,
  FLASHIF_ERASEKO,
  FLASHIF_WRITINGCTRL_ERROR,
  FLASHIF_WRITING_ERROR,
  FLASHIF_PROTECTION_ERRROR
};

uint32_t GetFlashEndAddreess(void);
uint32_t Flash_Write(uint32_t destination, uint32_t *p_source, uint32_t length);
void WatchDog_init(void);
void Freedog(void);
uint32_t GetFlashSize(void);
uint32_t GetSramSize(void);
uint32_t GetCPUID(void);
#endif //__BSP_H
